package cn.jsj.onclock.management;

import lombok.extern.slf4j.Slf4j;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.io.*;

/**
 * 这是一个工厂类，读取Excel模板。由于POI提供的XSSFWorkbook对象是线程不安全的，无法使用单例模式，所以无法使用单例Bean注入。
 * XSSFWorkbook没有提供拷贝构造方法，也没有实现Serializable接口或Cloneable接口。于是很难进行多例注入。
 * 可以使用反射深拷贝的方式完成多例注入，但是这个方式我个人非常不喜欢。
 * 这里是在程序开始运行时，先用文件输入流读取一次Excel模板文件，将读到的byte数组保存到ByteArrayOutputStream，然后通过byte数组拷贝实现的对象间接复制。
 *
 * @author 卢斌
 */
@Slf4j
@Component
public class ExcelWorkBookFactory {

    private final ByteArrayOutputStream byteArrayOutputStream;

    @Autowired
    public ExcelWorkBookFactory(ByteArrayOutputStream byteArrayOutputStream) {
        this.byteArrayOutputStream = byteArrayOutputStream;
    }

    public XSSFWorkbook getWorkbook() {

        // 虽然是输入输出流操作，但这是内存流，性能远高于文件流。
        // 注意这里的ByteArrayInputStream不需要关闭输入流，因为ByteArrayInputStream的close()方法是一个空实现方法，JDK作者可能只是希望开发者维持自己的编程习惯或者迎合面向对象规范。
        // 同样的ByteArrayOutputStream也不需要关闭输出流，也是因为其close()方法是一个空实现方法。
        ByteArrayInputStream inputStream = new ByteArrayInputStream(byteArrayOutputStream.toByteArray());
        XSSFWorkbook workbook = null;
        try {
            workbook = new XSSFWorkbook(inputStream);
        } catch (IOException e) {
            e.printStackTrace();
        }

        log.info("复制Byte数组，生成XSSFWorkbook对象");
        return workbook;
    }

}
